package com.guozinhs.auto.util.get;

import java.beans.Introspector;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 获取类的属性
 *
 * @Author: GuoZi
 * @Date: 2022/2/22 11:19
 */
public class Get {

    private static final String PREFIX_GETTER = "get";
    private static final String PREFIX_SETTER = "set";
    private static final String METHOD_NAME_CONSUMER = "accept";
    private static final String METHOD_WRITE_REPLACE = "writeReplace";

    /**
     * 获取对象属性名
     * <p>
     * Get.name(StateNode::getId) -> "id"
     *
     * @param name 操作类型
     * @param <T>  入参对象Class
     * @param <R>  返回的结果字段串
     * @return 属性名
     */
    public static <T, R> String name(TypeFunction<T, R> name) {
        return getLambdaColumnName(name);
    }

    /**
     * 获取对象属性类型
     * <p>
     * Get.name(StateNode::getId) -> Long.class
     *
     * @param name 操作类型
     * @param <T>  入参对象Class
     * @param <R>  返回的结果字段串
     * @return 属性名
     */
    public static <T, R> Class<R> aClass(TypeFunction<T, R> name) {
        return (Class<R>) getLambdaColumnClass(name);
    }

    /**
     * 获取类的属性类型
     *
     * @param lambda 方法的引用
     * @return String 属性类型
     */
    private static Class<?> getLambdaColumnClass(Serializable lambda) {
        try {
            Method method = lambda.getClass().getDeclaredMethod(METHOD_WRITE_REPLACE);
            method.setAccessible(Boolean.TRUE);
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(lambda);
            String signature = serializedLambda.getImplMethodSignature();
            signature = signature.substring(signature.indexOf(")") + 1);
            // 不考虑数组类型
            if (signature.startsWith(JNIEnums.ARRAY.getKey())) {
                return null;
            }
            if (signature.startsWith(JNIEnums.OBJECT.getKey())) {
                // 去掉开头的'L', 末尾的';'
                String className = signature.substring(1, signature.length() - 1);
                // 将'/'替换为'.'
                className = className.replace("/", ".");
                return Class.forName(className);
            }
            JNIEnums jniEnums = JNIEnums.getByKey(signature);
            if (Objects.isNull(jniEnums)) {
                return null;
            }
            return jniEnums.getAClass();
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取类的属性名
     *
     * @param lambda 方法的引用
     * @return String 属性名
     */
    private static String getLambdaColumnName(Serializable lambda) {
        try {
            Method method = lambda.getClass().getDeclaredMethod(METHOD_WRITE_REPLACE);
            method.setAccessible(Boolean.TRUE);
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(lambda);
            String getter = serializedLambda.getImplMethodName();
            String methodName = serializedLambda.getFunctionalInterfaceMethodName();
            String replace = PREFIX_GETTER;
            if (METHOD_NAME_CONSUMER.equals(methodName)) {
                replace = PREFIX_SETTER;
            }
            return Introspector.decapitalize(getter.replace(replace, ""));
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

}
